package zero.tech.games.logic.service;

import java.util.Map;
import java.util.Set;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import com.alibaba.fastjson.JSONObject;

import zero.tech.core.ZeroContext;
import zero.tech.core.data.JwtUtil;
import zero.tech.core.data.Resp;
import zero.tech.core.data.SimpleUser;
import zero.tech.core.event.service.api.EventService;
import zero.tech.core.snow.SnowIdUtil;
import zero.tech.core.work.WorkManager;
import zero.tech.games.api.RemoteTrade;
import zero.tech.games.api.RemoteUser;
import zero.tech.games.common.ClubMemberUtil;
import zero.tech.games.common.Code;
import zero.tech.games.common.FrozenUtil;
import zero.tech.games.common.GameConfig;
import zero.tech.games.common.UserLastRoomUtil;
import zero.tech.games.common.UserRoleUtil;
import zero.tech.games.common.data.UserLastRoom;
import zero.tech.games.entity.games.Club;
import zero.tech.games.entity.games.ClubMember;
import zero.tech.games.entity.games.UserRole;
import zero.tech.games.logic.common.CacheRoom;
import zero.tech.games.logic.common.GameBase;
import zero.tech.games.logic.common.Room;
import zero.tech.games.logic.common.RoomCache;
import zero.tech.games.logic.data.DissolutionData;
import zero.tech.games.logic.data.LogicEventType;
import zero.tech.games.logic.data.RoomStatus;
import zero.tech.games.logic.data.ServerData;
import zero.tech.games.logic.data.consts.LOGICCMD;
import zero.tech.games.logic.service.api.ILogicService;
import zero.tech.games.logic.util.LogicUtil;
import zero.tech.games.logic.util.PckUtil;
import zero.tech.games.logic.work.room.RecoveryRoomInit;
import zero.tech.wsnet.controller.CacheOnline;
import zero.tech.wsnet.controller.LogicController;
import zero.tech.wsnet.data.Message;
import zero.tech.wsnet.net.WebClient;
@Service
public class LogicServiceImpl implements ILogicService{
	@Autowired
	private UserLastRoomUtil userLastRoomUtil;
	@Autowired
	private UserRoleUtil userRoleUtil;
	@Autowired
	private EventService eventService;
	@Autowired
	private SnowIdUtil snowIdUtil;
	@Autowired
	private RemoteTrade remoteTrade;
	@Autowired
	private RemoteUser remoteUser;
	@Autowired
	private ClubMemberUtil clubMemberUtil;
	@Autowired
	private FrozenUtil frozenUtil;
	@Value("${spring.application.name}")
	private String service_id;
	@Override
	public void gameUpdateBatch(Room room, String joiners, String joiners_ai, Map<Integer, Long> gold_change_map,Map<Integer, Long> water_map) {
		if(!gold_change_map.isEmpty()||!water_map.isEmpty()) {
			String order_id=snowIdUtil.createId();
			int club_id=room.getClub().getClub_id();
			int game_id=room.getGame_id();
			int rule_id=-1;
			String room_id=room.getRoom_id();
			int room_times=room.getRoom_times();
			String room_name=room.getGameConfig().getName();
			int total_times=room.getGameConfig().getTotal_times();
			boolean ok = false;
			while (!ok) {
				try {
					Resp resp=remoteTrade.gameUpdateBatch(order_id,club_id, game_id, room_id,rule_id,room_times,room_name,total_times,joiners,joiners_ai==null?"":joiners_ai,JSONObject.toJSONString(gold_change_map), JSONObject.toJSONString(water_map));
					if(resp!=null&&Code.OK.equals(resp.getCode())) {
						ok=true;
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
				if (ok) {
					updateToGateSuccess(room, club_id,gold_change_map.keySet());
				} else {
					try {
						Thread.sleep(5000);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
		}
	}

	
	private void updateToGateSuccess(Room room, int club_id, Set<Integer> uids) {
		if(!uids.isEmpty()) {
			int index=0;
			int[] keys=new int[uids.size()];
			for(Integer uid:uids) {
				keys[index++]=uid;
			}
			Map<Integer,ClubMember> clubMemberMap=clubMemberUtil.getClubMemberBatch(club_id,keys);
			for(ClubMember clubMember:clubMemberMap.values()) {
				int uid=clubMember.getUid();
				long new_gold = clubMember.getTea();
				LogicController logicController =room.getAllControllers().get(uid);
				logicController.setGold(new_gold);
				logicController.setGold_from_gate(new_gold);
			}
		}
	}


	@Override
	public Resp roomCreated(Room room,SimpleUser simpleUser) {
		int uid=simpleUser.getUid();
		UserRole userRole=userRoleUtil.getUserRole(uid);
		LogicController online=new LogicController(new WebClient(null, String.valueOf(uid)), simpleUser,room.getRoom_id(),userRole.getRole_id());
		userLastRoomUtil.insertOrUpdate(PckUtil.packageUserLastRoom(room,uid));
		return joinRoom(room, online);
	}
	
	
	@Override
	public Resp roomJoined(Room room, SimpleUser simpleUser) {
		int uid=simpleUser.getUid();
		UserRole userRole=userRoleUtil.getUserRole(uid);
		LogicController online=new LogicController(new WebClient(null, String.valueOf(uid)), simpleUser,room.getRoom_id(),userRole.getRole_id());
		userLastRoomUtil.insertOrUpdate(PckUtil.packageUserLastRoom(room,uid));
		return joinRoom(room,online);
	}
	
	@Override
	public void reqRoomInfo(WebClient webClient, String token,String room_id) {
		SimpleUser simpleUser=JwtUtil.parseJWT(token);
		Assert.notNull(simpleUser,"simpleUser此时应该不能为null");
		int uid=simpleUser.getUid();
		Room room=null;
		UserLastRoom userLastRoom=userLastRoomUtil.getUserLastRoom(String.valueOf(uid));
		/*****************此处玩家在游戏未开始时掉线会清理掉最后房间信息,因此客户端重连时将取不到最后房间信息,
		 * 需要由客户端自己传递过来room_id进行获取数据******************/
		if(userLastRoom==null) {
			System.out.println("房间中断线重连");
			room=CacheRoom.getCache().getRooms().get(room_id);
			if(room==null) {
				webClient.sendMessage(Message.build(LOGICCMD.RES_ROOMINFO, Resp.build(Code.ROOM_NOT_EXSIST, "房间已不存在")));
				return;
			}
			Resp resp=LogicUtil.joinRoom(room, simpleUser);
			if(!Code.OK.equals(resp.getCode())) {
				webClient.sendMessage(Message.build(LOGICCMD.RES_ROOMINFO, Resp.build(Code.ROOM_NOT_EXSIST, "房间已不存在")));
				return;
			}
		}else {
			room_id=userLastRoom.getRoom_id();
			String club_id=userLastRoom.getClub_id();
			room=CacheRoom.getCache().getRooms().get(room_id);
			if(room==null) {
				LogicUtil.clearRoom(uid, room_id, club_id);
				webClient.sendMessage(Message.build(LOGICCMD.RES_ROOMINFO, Resp.build(Code.ROOM_NOT_EXSIST, "房间已不存在")));
				return;
			}
		}
		UserRole userRole=userRoleUtil.getUserRole(uid);
		LogicController online=new LogicController(webClient, simpleUser,room_id,userRole.getRole_id());
		CacheOnline.getCache().online(online);
		WorkManager.getManager().submit(RecoveryRoomInit.class,room,online);
	}


	@Override
	public void reqReady(Room room, LogicController controller) {
		int room_status=room.getRoom_status();
		if(room_status!=RoomStatus.DEFAULT&&room_status!=RoomStatus.WAIT_NEXT_ROUND) {
			controller.getWebClient().sendMessage(Message.build(LOGICCMD.RES_READY, Resp.build(Code.CANT_OPERATE, "当前不能操作")));
			return;
		}
		
		//准备时必须要钱够才能准备
		Boolean can_ready=eventService.engineCallBack(LogicEventType.READY_CHECK_MONEY, room,controller);
		if(can_ready==null||!can_ready) {
			controller.getWebClient().sendMessage(Message.build(LOGICCMD.RES_READY, Resp.build(Code.MONEY_NOT_ENOUGH, "钱不够不能准备")));
			return;
		}
		RoomCache roomCache=room.getRoomCache();
		if(roomCache.getWatchers().contains(controller.getId())) {
			controller.getWebClient().sendMessage(Message.build(LOGICCMD.RES_READY, Resp.build(Code.CANT_OPERATE, "观战者不能准备")));
			return;
		}
		if(roomCache.getTaotais().contains(controller.getId())) {
			controller.getWebClient().sendMessage(Message.build(LOGICCMD.RES_READY, Resp.build(Code.CANT_OPERATE, "已经被淘汰不能准备")));
			return;
		}
		int uid=controller.getId();
		GameBase gameBase = room.getGameBase();
		if(gameBase.getReadys().containsKey(uid)) {
			return;
		}
		gameBase.getReadys().put(uid, System.currentTimeMillis());
		controller.getWebClient().sendMessage(Message.build(LOGICCMD.RES_READY, Resp.build(Code.OK, "准备了")));
		//通知其他人有人准备了
		LogicUtil.broadRoomAllControllersInclude(room, Message.build(LOGICCMD.NOTIFY_SOMEONE_READY, Resp.build(Code.OK, "某人准备了",PckUtil.packageNotifySomeOneReady(controller))),controller);		
	}
	
	
	private Resp joinRoom(Room room,LogicController online) {
		CacheOnline.getCache().online(online);
		int uid=online.getId();
		String room_id=room.getRoom_id();
		LogicController oldonline=room.getAllControllers().get(uid);
		GameConfig gameConfig = room.getGameConfig();
		synchronized (room.getJoin_lock()) {
			if(oldonline==null) {
				if(ServerData.isClosed(room.getGame_id())) {
					//服务器关闭
					userLastRoomUtil.delete(String.valueOf(uid), room_id);
					return Resp.build(Code.HAVE_BEING_FROZEN, "服务器维护中...稍后再试");
				}
				if(room.getClub()!=null) {
					boolean infrozen=frozenUtil.infrozenlist(room.getClub().getClub_id(),uid);
					if(infrozen) {
						userLastRoomUtil.delete(String.valueOf(uid), room_id);
						return Resp.build(Code.HAVE_BEING_FROZEN, "被冻结了不能参与游戏");
					}
				}
				
				int room_status=room.getRoom_status();
				int watcher=gameConfig.getWatcher();
				if(room_status!=RoomStatus.DEFAULT&&watcher==0) {
					//游戏开始了,加入房间失败了,清除最后房间信息
					userLastRoomUtil.delete(String.valueOf(uid), room_id);
					return Resp.build(Code.GAME_IS_BEGIN, "游戏已经开始了");
				}
				
				Integer pos=LogicUtil.getFreePos(room);
				if(pos==null) {
					//加入失败了,清除最后房间信息
					userLastRoomUtil.delete(String.valueOf(uid), room_id);
					return Resp.build(Code.ROOM_PERSON_FULL, "房间人满了");
				}
				room.getSeats().put(pos,uid);
				if(room_status!=RoomStatus.DEFAULT&&watcher==1) {
					RoomCache roomCache = room.getRoomCache();
					roomCache.getWatchers().add(uid);
				}
			}else {
				if(ServerData.isClosed(room.getGame_id())) {
					//服务器关闭
					return Resp.build(Code.HAVE_BEING_FROZEN, "服务器维护中...稍后再试");
				}
			}
			init(room,online,oldonline);
		}
		LogicUtil.roomNodeUpdate(room);
		return Resp.build(Code.OK, "成功",room.getRoomNode());
	}


	private void init(Room room, LogicController online, LogicController oldonline) {
		int uid=online.getId();
		if(oldonline!=null) {
			online.setWin(oldonline.getWin());
			online.setGold(oldonline.getGold());
			online.setGold_from_gate(oldonline.getGold_from_gate());
			online.setRoomId(room.getRoom_id());
			online.setRole_id(oldonline.getRole_id());
			LogicUtil.someoneOnline(room,online);
		}else {
			long gold=0;
			long win=0;
			Club club=room.getClub();
			if(club!=null) {
				int club_id=room.getClub().getClub_id();
				ClubMemberUtil clubMemberUtil=ZeroContext.getInstance(ClubMemberUtil.class);
				ClubMember clubMember=clubMemberUtil.getClubMember(club_id,uid);
				gold=clubMember.getTea();
			}
			online.setWin(win);
			online.setGold(gold);
			online.setGold_from_gate(gold);
			online.setRoomId(room.getRoom_id());
			LogicUtil.broadRoomAllControllersInclude(room, Message.build(LOGICCMD.NOTIFY_SOMEONE_JOIN, Resp.build(Code.OK, "某人加入房间",PckUtil.packageNotifySomeOneJoin(room,online))),online);
		}	
		room.getAllControllers().put(uid, online);
	}


	@Override
	public void notifyBigCalculate(Room room) {
		
	}


	@Override
	public void reqDissolution(Room room, LogicController controller) {
		int room_status=room.getRoom_status();
		if(room_status==RoomStatus.DEFAULT) {
			reqLeave(room, controller);
			return;
		}
		RoomCache roomCache =  room.getRoomCache();
		if(room.isWatcher(controller.getId())) {
			controller.getWebClient().sendMessage(Message.build(LOGICCMD.RES_DISSOLUTION, Resp.build(Code.CANT_OPERATE, "当前不能解散")));
			return;
		}
		if(room_status==RoomStatus.CALCULATING) {
			controller.getWebClient().sendMessage(Message.build(LOGICCMD.RES_DISSOLUTION, Resp.build(Code.CANT_OPERATE, "当前不能解散")));
			return;
		}
		DissolutionData dissolutionData=roomCache.getDissolutionData();
		if(!dissolutionData.getDissolutions().isEmpty()) {
			//有人已经发起了解散房间
			return;
		}
		int uid=controller.getId();
		dissolutionData.setApply_uid(uid);
		dissolutionData.getDissolutions().put(uid, true);
		dissolutionData.setDissolution_apply_time(System.currentTimeMillis());
		dissolutionData.setDissolution_aplly_count(dissolutionData.getDissolution_aplly_count()+1);
		controller.getWebClient().sendMessage(Message.build(LOGICCMD.RES_DISSOLUTION, Resp.build(Code.OK, "申请解散房间成功",PckUtil.packageResDissolutionData(dissolutionData))));
		LogicUtil.broadRoomControllersWithoutWatcherAndTaotais(room, Message.build(LOGICCMD.NOTIFY_DISSOLUTION_APPLY_ARRIVED, Resp.build(Code.OK, "解散申请到达",PckUtil.packageNotifyDissolutionApplyArrived(uid,dissolutionData))), controller);		
	}


	@Override
	public void reqDissolutionAnswer(Room room, LogicController controller, int agree) {
		int room_status=room.getRoom_status();
		if(room.isWatcher(controller.getId())) {
			//观战者不能应答
			controller.getWebClient().sendMessage(Message.build(LOGICCMD.RES_DISSOLUTION_ANSWER, Resp.build(Code.CANT_OPERATE, "当前不能操作")));
			return;
		}
		if(room_status==RoomStatus.DEFAULT||room_status==RoomStatus.CALCULATING) {
			controller.getWebClient().sendMessage(Message.build(LOGICCMD.RES_DISSOLUTION_ANSWER, Resp.build(Code.CANT_OPERATE, "当前不能操作")));
			return;
		}
		RoomCache roomCache = room.getRoomCache();
		DissolutionData dissolutionData=roomCache.getDissolutionData();
		if(dissolutionData.getDissolutions().isEmpty()) {
			//没人发起解散申请
			return;
		}
		int uid=controller.getId();
		if(dissolutionData.getDissolutions().containsKey(uid)) {
			//已经处理过
			return;
		}
		if(agree==0) {
			//拒绝
			dissolutionData.getDissolutions().put(uid, false);
		}else {
			//同意
			dissolutionData.getDissolutions().put(uid,true);
		}
		controller.getWebClient().sendMessage(Message.build(LOGICCMD.RES_DISSOLUTION_ANSWER, Resp.build(Code.OK, "应答解散房间成功",PckUtil.packageResDissolution(agree))));
		LogicUtil.broadRoomControllersWithoutWatcherAndTaotais(room, Message.build(LOGICCMD.NOTIFY_DISSOLUTION_ANSWER_ARRIVED, Resp.build(Code.OK, "应答解散到达",PckUtil.packageNotifyDissolutionAnswerArrived(uid,agree))), controller);
		//同意数量达到一个预值时,房间解散
		int size=room.getControllersWithoutWatcherAndTaotai().size();
		int count=size;
		int agree_count=LogicUtil.agreeDissolutionCount(dissolutionData);
		if(agree_count>=count) {
			//所有人都同意解散了
			eventService.engineNotify(LogicEventType.ROOM_DISSOLUTION_FREE, room);
		}else {
			if(dissolutionData.getDissolutions().size()>=size) {
				//所有人都表决了,但是没有达到解散的条件,客户端面板消失
				LogicUtil.broadRoomControllersWithoutWatcherAndTaotais(room, Message.build(LOGICCMD.NOTIFY_DISSOLUTION_ROOM_ARRIVED, Resp.build(Code.OK, "解散到达",PckUtil.packageNotifyDissolutionRoomArrived(0))));
				long pass=System.currentTimeMillis()-dissolutionData.getDissolution_apply_time();
				dissolutionData.getDissolutions().clear();
				dissolutionData.setDissolution_apply_time(null);
				dissolutionData.setApply_uid(null);
				eventService.engineNotify(LogicEventType.ROOM_DISSOLUTION_RUNTIMER,room,pass);
			}
		}
	}


	@Override
	public void reqLeave(Room room, LogicController controller) {
		int room_status=room.getRoom_status();
		if(room_status==RoomStatus.DEFAULT) {
			LogicUtil.freeRoomController(room,controller,true,Message.build(LOGICCMD.RES_LEAVE, Resp.build(Code.OK, "强制离开成功")));
		}else {
			RoomCache roomCache = room.getRoomCache();
			Set<Integer> taotais=roomCache.getTaotais();
			if(taotais.contains(controller.getId())) {
				//游戏开始了,淘汰玩家离开,提前结算淘汰者并(并未被结算的)
				eventService.engineNotify(LogicEventType.PLAYER_TAOTAI_LEAVE, room,controller);
			}
		}
	}

	@Override
	public void reqExitAutoDeposit(Room room, LogicController controller) {
		controller.getWebClient().sendMessage(Message.build(LOGICCMD.RES_EXIT_AUTO_DEPOSIT, Resp.build(Code.OK, "退出托管成功",PckUtil.packageResExitAutoDeposit(controller))));
		LogicUtil.cancleAutoDeposit(room,controller);	
	}


	@Override
	public void gameUpdateDiamondBatch(Room room, Map<Integer, Long> diamondchangemap) {
		if(!diamondchangemap.isEmpty()) {
			String order_id=snowIdUtil.createId();
			int game_id=room.getGame_id();
			String room_id=room.getRoom_id();
			int room_times=room.getRoom_times();
			String room_name=room.getGameConfig().getName();
			int total_times=room.getGameConfig().getTotal_times();
			boolean ok = false;
			while (!ok) {
				try {
					Resp resp=remoteUser.gameUpdateDiamondBatch(order_id, game_id, room_id,room_times,room_name,total_times,JSONObject.toJSONString(diamondchangemap));
					if(resp!=null&&Code.OK.equals(resp.getCode())) {
						ok=true;
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
				if (ok) {
					System.out.println("砖石更新成功");
				} else {
					try {
						Thread.sleep(5000);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
		}		
	}


	@Override
	public String getServiceId() {
		return this.service_id;
	}


}
